﻿<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>svg时钟（转载）</title>
<script src="../js/jquery.min.js"></script>
<style>
body {
	background:#1e2730;
	font-family:Arial;
}
svg {
	width:100vmin;
	margin:0 auto;
	display:block;
}
circle {
	fill:none;
	stroke-width:3;
}
#secondsPath {
	stroke-width:3;
	pointer-events:none;
	stroke-linecap:round;
}
#minPath {
	stroke-width:3;
	pointer-events:none;
	stroke-linecap:round;
}
#hoursPath {
	stroke-width:3;
	pointer-events:none;
	stroke-linecap:round;
}
text {
	dominant-baseline:central;
	text-anchor:middle;
	font-size:5px;
	fill:Linen;
}
svg text::selection {
	background:none;
}
#hub {
	fill:#24303a;
	stroke-width:0;
}
#toggle,#reset {
	cursor:pointer;
}
</style>
</head>
<body>
<svg viewBox="0 0 50 50">
    <g>
        <circle id="secondsCirc" r="14" stroke="#24303a"></circle>
        <path id="secondsPath" d="" fill="transparent" stroke="#1ed5f6"></path>

        <circle id="minCirc" r="10" stroke="#24303a"></circle>
        <path id="minPath" d="" fill="transparent" stroke="#f61ed5"></path>

        <circle id="hoursCirc" r="6" stroke="#24303a"></circle>
        <path id="hoursPath" d="" fill="transparent" stroke="#d5f61e"></path>


        <circle id="hub" cx="0" cy="0" r="3.5" fill="#24303a"></circle>
    </g>
    <text id="text" transform="translate(25 5)">00:00:00</text>
    <text id="toggle" transform="translate(15 45)">STOP</text>
    <text id="reset" transform="translate(37 45)">RESET</text>
</svg>

<script>
 const rad = Math.PI / 180;
    let requestId = null;
    let stop = false;
    const svg = document.querySelector("svg");
    const g = document.querySelector("g");

    const TIME = "16:07:50";
    // counters
    let h = parseInt(TIME.split(":")[0]);
    let m = h * 60 + parseInt(TIME.split(":")[1]);
    let s = h * 60 * 60 + m * 60 + parseInt(TIME.split(":")[2]);
    //data
    let circles = {
        s: {
            path: secondsPath,
            divisions: 60,
            r: secondsCirc.getAttribute("r"),
            stroke: "#1ed5f6",
            start: (parseInt(TIME.split(":")[2])) % 60
        },
        m: {
            path: minPath,
            divisions: 60,
            r: minCirc.getAttribute("r"),
            stroke: "#f61ed5",
            start: (parseInt(TIME.split(":")[1])) % 60
        },
        h: {
            path: hoursPath,
            divisions: 24,
            r: hoursCirc.getAttribute("r"),
            stroke: "#d5f61e",
            start: (parseInt(TIME.split(":")[0])) % 24
        }
    };

    let translation = {
        x: 25,
        y: 25
    }; //translate
    let rotation = -90;
    let rot = -(rotation * rad);
    g.setAttributeNS(
        null,
        "transform",
        `translate(${translation.x} ${translation.y}) rotate(${rotation})`
    );

    const spring = 0.09;
    const friction = 0.8;

    class Clock {
        constructor(o) {
            this.path = o.path;
            this.divisions = o.divisions; //24 || 60
            this.R = o.r;
            this.start = o.start;
            this.strokeDashoffset = 0;
            this.definePath(this.path);
            this.vel = 0;
        }

        update(time) {
            let t = time % this.divisions;

            this.strokeLength = this.target;
            this.target = t * this.pathLength / this.divisions;

            if (this.pathLength - this.strokeLength <= this.delta) {
                this.strokeDashoffset += this.pathLength;
                this.strokeLength = 0.1;
            }
        }

        updateStrokeLength() {
            this.dist = this.target - this.strokeLength;
            this.acc = this.dist * spring;
            this.vel += this.acc;
            this.vel *= friction;
            this.strokeLength += this.vel;
            this.path.style.strokeDasharray = `${this.strokeLength},${this.pathLength -
            this.strokeLength}`;
            this.path.style.strokeDashoffset = this.strokeDashoffset;

        }

        definePath() {
            let d =
                "M" +
                this.R +
                "," +
                0 +
                "  A" +
                this.R +
                "," +
                this.R +
                " 0 " +
                1 +
                "," +
                1 +
                this.R +
                "," +
                -1 +
                "z";
            //y-1: the circles are rotated 90 degs

            this.path.setAttributeNS(null, "d", d);
            this.pathLength = this.path.getTotalLength();
            this.delta = this.pathLength / this.divisions;
            this.strokeLength = this.start * this.delta;
            this.target = this.strokeLength;
            this.path.style.strokeDasharray = `${this.strokeLength},${this.pathLength -
            this.strokeLength}`;
            this.path.style.strokeDashoffset = this.strokeDashoffset;
        }
    }

    let secondsTrack = new Clock(circles.s);
    let minTrack = new Clock(circles.m);
    let hoursTrack = new Clock(circles.h);

    let sid = setInterval(setCron, 1000);

    function addZero(i) {
        if (i < 10) {
            i = "0" + i;
        }
        return i;
    }

    function setText(h, m, s) {
        text.textContent =
            addZero(h % 24) + ":" + addZero(m % 60) + ":" + addZero(s % 60);
    }

    setText(h, m, s);

    function Animation() {
        requestId = window.requestAnimationFrame(Animation);
        secondsTrack.updateStrokeLength();
        minTrack.updateStrokeLength();
        hoursTrack.updateStrokeLength();
    }
    Animation();



    reset.addEventListener("click", resetCron, false);

    function resetCron() {
        secondsTrack = new Clock(circles.s);
        minTrack = new Clock(circles.m);
        hoursTrack = new Clock(circles.h);

        h = parseInt(TIME.split(":")[0]);
        m = h * 60 + parseInt(TIME.split(":")[1]);
        s = h * 60 * 60 + m * 60 + parseInt(TIME.split(":")[2]);

        setText(h, m, s);
    }

    function setCron() {
        secondsTrack.update(s);
        if (s % 60 == 0) {
            minTrack.update(m);
        }
        if (s % (60 * 60) == 0) {
            hoursTrack.update(h);
        }

        setText(h, m, s);

        s++;
        if (s % 60 == 0) {
            m++;
        }
        if (s % (60 * 60) == 0) {
            h++;
        }
    }

    toggle.addEventListener("click", function() {

        if (stop) {
            stop = false;
            toggle.textContent = "STOP";
            sid = setInterval(setCron, 1000);

        } else {
            stop = true;
            toggle.textContent = "GO";
            clearInterval(sid);
        }
    }, false);
</script>

</body>
</html>
